home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xvmahjon.por / xvmahjon / xvmahjongg / mahjongg.c < prev    next >
C/C++ Source or Header  |  1991-12-20  |  44KB  |  1,812 lines

  1. /*
  2.  * XView port of Mahjongg done by Stan K Tazuma, 8/91-9/91
  3.  * Copyright 1991.
  4.  *
  5.  * $Header: /home/sirius/skt/cmds/src/sun/mj/RCS/mahjongg.c,v 2.5 91/12/20 14:40:29 skt Exp $
  6.  *
  7.  *    Revision History
  8.  *    ----------------
  9.  *
  10.  *    2.0 First release of XView version - 12/20/91
  11.  *
  12.  */
  13. static char Release_info[] = "Release 2.0";
  14.  
  15. /*
  16.  *    Copyright 1988, Mark Holm
  17.  *            Exceptions
  18.  *
  19.  *    Acknowledgments to Dorothy Robinson for her artistic
  20.  *     abilities in drawing the icons and to Jim Batch for
  21.  *     technical support and graphical concepts (which I abandoned in favor
  22.  *       of the easy way out).
  23.  *
  24.  *    Permission is given to copy and distribute for non-profit purposes.
  25.  *
  26.  *    Revision History
  27.  *    ----------------
  28.  *
  29.  *    1.0 Initial release
  30.  *
  31.  *    1.1 removed non-working reverse video cursor code
  32.  *        added blank tiles for hidden tiles to stop cheating.
  33.  *
  34.  *    1.2 incorporated sun fix for panel messages and added new
  35.  *         shuffling algorithm.
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include <sys/types.h>
  40. #include <sys/time.h>
  41. #include <xview/xview.h>
  42. #include <xview/panel.h>
  43. #include <xview/canvas.h>
  44. #include <xview/icon.h>
  45. #include <xview/svrimage.h>
  46. #include <xview/cms.h>
  47. #include <xview/font.h>
  48. #include <xview/cursor.h>
  49.  
  50. #include "mahjongg.h"
  51.  
  52. void            die();
  53. void            build_image();
  54. void            place_tiles();
  55.  
  56. Icon icon;
  57.  
  58. /* externals */
  59.  
  60. extern void        quit_proc();
  61. extern void        undo_proc();
  62. extern void        new_proc();
  63. extern void        again_proc();
  64. extern void        help_proc();
  65. extern void        board_num_proc();
  66. extern void        play_back_proc();
  67. extern void        play_event_proc();
  68. extern void        panel_msg();
  69. extern void        message_panel_event_proc();
  70.  
  71. extern short        stick_image[];
  72. extern short        confirm_image[];
  73. extern short        wait_image[];
  74.  
  75. extern int        undo_count;
  76.  
  77. /* overlap globals */
  78.  
  79. Frame            main_frame;
  80. Panel            message_panel;
  81. Canvas            play_canvas;
  82. Xv_Window        Play_area;
  83. Panel_item        TL_hundred;
  84. Panel_item        TL_ten;
  85. Panel_item        TL_one;
  86. Panel_item        message;
  87. Panel_item        tile[144];
  88.  
  89. Xv_Cursor        play_cursor;
  90. Server_image        play_cursor_si;
  91. Server_image        stick_cursor_si;
  92. Server_image        confirm_cursor_si;
  93. Server_image        wait_cursor_si;
  94.  
  95. #define NUM_ICON_COUNT        10
  96. Pixrect *Num_icon_mpr[NUM_ICON_COUNT];
  97. Server_image Num_icon_si[NUM_ICON_COUNT];
  98.  
  99. /* 42 game tiles plus 1 for the blank tile (which comes at the end) */
  100. #define TILE_ICON_COUNT        (42 + 1)
  101. Pixrect *Tile_icon_mpr[TILE_ICON_COUNT];
  102. Server_image Tile_icon_si[TILE_ICON_COUNT];
  103.  
  104. boolean Use_num_server_images = TRUE;
  105. boolean Use_tile_server_images = TRUE;
  106.  
  107. boolean Use_panel_control_cms = FALSE;
  108. boolean Use_colored_buttons = TRUE;
  109. boolean Use_canvas_control_cms = FALSE;
  110. #define panel_color(c)    (Use_panel_control_cms ? CMS_CONTROL_COLORS + c : c)
  111. boolean Use_canvas_dynamic_cms = TRUE;    /* use a dynamic CMS rather than a
  112.                      * static one */
  113.  
  114. boolean Invert_tiles = FALSE;        /* if true, tiles will be inverted;
  115.                      * used for BandW mode only */
  116. boolean Switch_bg_fg = FALSE;        /* if true, the bg and fg colors in
  117.                      * the canvas will be switched; only
  118.                      * used for BandW mode */
  119. boolean Use_error_bells = FALSE;    /* if true, then the bell will be
  120.                      * sounded when the player makes an
  121.                      * error during play */
  122.  
  123. boolean            BandW = FALSE;    /* if true, operate in Black and
  124.                      * White mode */
  125.  
  126. Tile            *board[144];
  127. Tile            board_tile[144]; 
  128.     /*
  129.      * Not the best way to do this, but I didn't want to
  130.      * change all the code that assumed that board[] was a pointer.
  131.      * The SunView code used malloc() for creating space for the
  132.      * tiles.  Since the space is never freed, and we always need to
  133.      * have a struct for each tile, I decided to just statically allocate
  134.      * the space.  Each board[i] is initialized to board_tile[i] in
  135.      * the build_image() routine.
  136.      */
  137.  
  138. Selected        selected[2];
  139. int            tile_count;
  140. char            state[256];
  141.  
  142. int    Display_depth;
  143.  
  144.  
  145. /* local globals */
  146.  
  147. Panel_item        board_num;
  148. int            seed;
  149.  
  150. char *Usage_msg =
  151. "Usage: mahjongg [-b] [-c] [-n #] [-P] [-PB] [-B] [-BB]\n\
  152. \t\t[-C] [-D] [-N] [-T] [-E]\n";
  153.  
  154. /* define color map */
  155.  
  156. #define NUM_COLORS    8
  157. #define Mahjongg_color_list    "black", "red", "green", "yellow", \
  158.                 "blue", "magenta", "cyan", "white"
  159. #define BLACK    0
  160. #define RED    1
  161. #define GREEN    2
  162. #define YELLOW    3
  163. #define BLUE    4
  164. #define MAGENTA    5
  165. #define CYAN    6
  166. #define WHITE    7
  167.  
  168. Cms    mahjongg_panel_cms;
  169. Cms    mahjongg_canvas_cms;
  170. Cms    mahjongg_icon_cms;
  171. unsigned char    Cms_inverse_table[256];
  172. Cms create_aligned_cms();
  173.  
  174. void repaint_proc();
  175. boolean Clear_msg = FALSE;        /* used only by build_image() and
  176.                      * place_tiles() to determine whether
  177.                      * or not to clear a certain message
  178.                      * and re-set the mouse cursor */
  179.  
  180. main(argc, argv)
  181. int argc;
  182. char **argv;
  183. {
  184.     int i;
  185.     int middle;
  186.     int button_x;            /* used for positioning buttons */
  187.     time_t tp;
  188.  
  189.     /* initialize random number generator seed */
  190.     time(&tp);
  191.     (void) initstate((unsigned) (tp % 255), state, 256); /* initialize random state array */
  192.     seed = RANDOM(20011);
  193.  
  194.     /* check for -help request before calling xv_init() */
  195.     if (argc > 1 &&
  196.         (strcmp(argv[1], "-help") == 0 ||
  197.          strcmp(argv[1], "-WH")   == 0)) {
  198.     print_help();
  199.     }
  200.  
  201.     xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
  202.  
  203.     /*
  204.      * Want to determine BandW before creating the frame, in order to
  205.      * use it to control the color stuff.
  206.      *
  207.      * But can't parse arguments until after the xv_init(), since it may
  208.      * have to strip out XView arguments.  Also don't want to process
  209.      * arguments before the random number stuff is initialized above.
  210.      */
  211.  
  212.     /* parse arguments */
  213.     for (argc--, argv++; argc > 0; argc--, argv++)
  214.     if (argv[0][0] = '-')
  215.         switch (argv[0][1]) {
  216.         case 'c': /* force color */
  217.         BandW = FALSE;
  218.         break;
  219.         case 'b': /* force black and white */
  220.         BandW = TRUE;
  221.         break;
  222.         case 'n': /* set board number */
  223.         if(argc-- == 0)
  224.             die(Usage_msg, 0);
  225.         argv++;
  226.             sscanf(argv[0] , "%d", &seed);
  227.         if (seed > 20011) {
  228.             printf("Board numbers must be < 20011");
  229.             seed %= 20011;
  230.         }
  231.         break;
  232.         case 'N':    /* use pixrects for the numbers in the panel */
  233.         Use_num_server_images = FALSE;
  234.         fprintf(stderr,
  235. "Note: you'll see warning messages when -N is used, but just ignore them.\n");
  236.         break;
  237.         case 'T':    /* use pixrects for the tiles */
  238.         Use_tile_server_images = FALSE;
  239.         break;
  240.         case 'P':    /* use a control cms for the panel */
  241.         Use_panel_control_cms = TRUE;
  242.         if (argv[0][2] == 'B')
  243.             Use_colored_buttons = FALSE;
  244.         break;
  245.         case 'B':    /* like 'b', but use a black background */
  246.         /* can do -B or -BB (black on black) */
  247.         BandW = TRUE;
  248.         if (argv[0][2] != 'B')
  249.             Invert_tiles = TRUE;
  250.         Switch_bg_fg = TRUE;
  251.         break;
  252.         case 'C':    /* use a control cms for the canvas */
  253.         Use_canvas_control_cms = TRUE;
  254.         Use_canvas_dynamic_cms = FALSE;
  255.         break;
  256.         case 'D':    /* don't use a dynamic cms for the canvas */
  257.         Use_canvas_dynamic_cms = FALSE;
  258.         break;
  259.         case 'E':    /* ring the bell on player errors */
  260.         Use_error_bells = TRUE;
  261.         break;
  262.  
  263.         default:
  264.         die(Usage_msg, 0);
  265.         break;
  266.         }
  267.     else
  268.         die(Usage_msg, 0);
  269.  
  270.     /* determine type of frame buffer and set BandW accordingly */
  271.     Display_depth = get_display_depth();
  272.     if (Display_depth < 2)
  273.     BandW = TRUE;
  274.  
  275.     if (BandW) {
  276.     Use_canvas_control_cms = FALSE;
  277.     Use_canvas_dynamic_cms = FALSE;
  278.     Use_colored_buttons = FALSE;
  279.     }
  280.  
  281.     /* create icon */
  282.     if (BandW) {
  283.     icon = xv_create(XV_NULL, ICON,
  284.             ICON_IMAGE,    &icon_image_pr,
  285.             NULL);
  286.     }
  287.     else {
  288.     /* if color then apply color icon to window icon */
  289.     icon = xv_create(XV_NULL, ICON,
  290.             ICON_IMAGE,    &cicon_image,
  291.             NULL);
  292.     }
  293.  
  294.     if (! BandW) {
  295.     /* set up colormap segments and related stuff */
  296.  
  297.     setup_cms();
  298.  
  299.     get_cms_inverse_table(mahjongg_canvas_cms);
  300.      }
  301.  
  302.     init_local_mem_rop();    /* set up a routine needed for pw_read()
  303.                  * to work */
  304.  
  305.     /* create main frame */
  306.    
  307.     main_frame = xv_create(NULL, FRAME,
  308.                 /*
  309.                  * Don't do this on the XView version; it
  310.                  * takes away the name stripe at the top of
  311.                  * the window.  The name stripe is useful
  312.                  * because of the quick iconize button.
  313.                  * Instead, just set the FRAME_LABEL to the
  314.                  * empty string, to get the same effect.
  315.                 FRAME_SHOW_LABEL,    FALSE,
  316.                 */
  317.                 FRAME_LABEL,        "",
  318.  
  319.                 /*
  320.                  * Set the X,Y coord's of the tool. If this
  321.                  * isn't done, the tool may come up with part
  322.                  * of the canvas window off-screen.  In this
  323.                  * situation the high-lighting (color
  324.                  * inversion) of the tiles happens
  325.                  * noticeably slower.  This was a tricky one
  326.                  * to figure out.
  327.                  */
  328.                 XV_X,            20,
  329.                 XV_Y,            20,
  330.  
  331.                 FRAME_ICON,        icon,
  332.                 XV_HEIGHT,        FRAME_Y_MAX,
  333.                 XV_WIDTH,        FRAME_X_MAX,
  334.  
  335.                 /* have to set WIN_CMS when creating the frame,
  336.                  * otherwise the icon doesn't get the right
  337.                  * colors (so can't create the FRAME first,
  338.                  * then set WIN_CMS later with xv_set()) */
  339.                 (BandW ? ATTR_NOP1 : WIN_CMS),
  340.                             mahjongg_icon_cms,
  341.                 NULL);
  342.  
  343.     /* set up the panel on the right hand side */
  344.  
  345.     message_panel = xv_create(main_frame, PANEL,
  346.             XV_HEIGHT,    MESS_Y_MAX,
  347.             XV_WIDTH,    MESS_X_MAX,
  348.             WIN_X,        0,
  349.             WIN_Y,        0,
  350.             (BandW ? ATTR_NOP1 : WIN_CMS),    mahjongg_panel_cms,
  351.  
  352.             /*
  353.              * The PANEL_EVENT_PROC is used to provide the same
  354.              * behavior that the SunView version provided by
  355.              * making use of WIN_INPUT_DESIGNEE (see commented
  356.              * out code below where the use of
  357.              * WIN_INPUT_DESIGNEE is shown).
  358.              * Also required for simulating this behavior is
  359.              * code in event.c that manipulates the event
  360.              * masks and changes PANEL_BACKGROUND_PROC
  361.              */
  362.             PANEL_EVENT_PROC,    message_panel_event_proc,
  363.  
  364.             XV_HELP_DATA,        "mahjongg:message_panel",
  365.             NULL);
  366.  
  367.     /* set up the icons */
  368.     init_num_icon_mprs();
  369.     init_tile_icon_mprs();
  370.  
  371.     if (BandW && Invert_tiles)
  372.     invert_tile_icon_mprs();
  373.  
  374.     if (Use_canvas_control_cms)
  375.     shift_tile_icon_mprs();
  376.  
  377.     if (Use_tile_server_images)
  378.     init_tile_icon_server_images();
  379.  
  380.     if (Use_panel_control_cms)
  381.     shift_num_icon_mprs();
  382.  
  383.     if (Use_num_server_images)
  384.     init_num_icon_server_images();
  385.  
  386.     /* create tile counters */
  387.  
  388.     TL_hundred = xv_create(message_panel, PANEL_MESSAGE,
  389.             PANEL_LABEL_IMAGE,    Use_num_server_images ?
  390.                            (Xv_opaque) Num_icon_si[1] :
  391.                            (Xv_opaque) Num_icon_mpr[1],
  392.             XV_Y,            100,
  393.             XV_X,            X_LOC,
  394.             XV_HELP_DATA,        "mahjongg:tiles_remaining",
  395.             NULL);
  396.  
  397.     TL_ten = xv_create(message_panel, PANEL_MESSAGE,
  398.             PANEL_LABEL_IMAGE,    Use_num_server_images ?
  399.                            (Xv_opaque) Num_icon_si[4] :
  400.                            (Xv_opaque) Num_icon_mpr[4],
  401.             XV_Y,            100,
  402.             XV_X,            X_LOC + W_BASE_TILE,
  403.             XV_HELP_DATA,        "mahjongg:tiles_remaining",
  404.             NULL);
  405.  
  406.     TL_one = xv_create(message_panel, PANEL_MESSAGE,
  407.             PANEL_LABEL_IMAGE,    Use_num_server_images ?
  408.                            (Xv_opaque) Num_icon_si[4] :
  409.                            (Xv_opaque) Num_icon_mpr[4],
  410.             XV_Y,            100,
  411.             XV_X,            X_LOC + (W_BASE_TILE * 2),
  412.             XV_HELP_DATA,        "mahjongg:tiles_remaining",
  413.             NULL);
  414.  
  415.  
  416.     /* create game label messages */
  417.  
  418.     /* determine middle of panel */
  419.  
  420.     middle = (MESS_X_MAX / 2);
  421.  
  422.     xv_create(message_panel, PANEL_MESSAGE,
  423.                 PANEL_LABEL_STRING,    "MAHJONGG",
  424.                 PANEL_LABEL_BOLD,    TRUE,
  425.                 XV_Y,            10,
  426.                 XV_X,            middle - 63,
  427.                 XV_HELP_DATA,        "mahjongg:credits",
  428.                 NULL);
  429.  
  430.     xv_create(message_panel, PANEL_MESSAGE,
  431.                 PANEL_LABEL_STRING,    "Copyright 1988",
  432.                 XV_Y,            25,
  433.                 XV_X,            middle - 71,
  434.                 XV_HELP_DATA,        "mahjongg:credits",
  435.                 NULL);
  436.  
  437.     xv_create(message_panel, PANEL_MESSAGE,
  438.                 PANEL_LABEL_STRING,    "Mark A. Holm",
  439.                 XV_Y,            40,
  440.                 XV_X,            middle - 65,
  441.                 XV_HELP_DATA,        "mahjongg:credits",
  442.                 NULL);
  443.  
  444.     xv_create(message_panel, PANEL_MESSAGE,
  445.                 PANEL_LABEL_STRING,    "Exceptions",
  446.                 XV_Y,            55,
  447.                 XV_X,            middle - 58,
  448.                 XV_HELP_DATA,        "mahjongg:credits",
  449.                 NULL);
  450.  
  451.     xv_create(message_panel, PANEL_MESSAGE,
  452.                 PANEL_LABEL_STRING,    "Tiles Remaining",
  453.                 XV_Y,            75,
  454.                 XV_X,            X_LOC + 38,
  455.                 XV_HELP_DATA,    "mahjongg:tiles_remaining",
  456.                 NULL);
  457.  
  458.     xv_create(message_panel, PANEL_MESSAGE,
  459.                 PANEL_LABEL_STRING,    "Ported to XView in",
  460.                 XV_Y,            25,
  461.                 XV_X,            middle + 290,
  462.                 XV_HELP_DATA,        "mahjongg:credits",
  463.                 NULL);
  464.     xv_create(message_panel, PANEL_MESSAGE,
  465.                 PANEL_LABEL_STRING,    "9/91 by S. K. Tazuma",
  466.                 XV_Y,            40,
  467.                 XV_X,            middle + 290,
  468.                 XV_HELP_DATA,        "mahjongg:credits",
  469.                 NULL);
  470.     xv_create(message_panel, PANEL_MESSAGE,
  471.                 PANEL_LABEL_STRING,    Release_info,
  472.                 XV_Y,            55,
  473.                 XV_X,            middle + 290,
  474.                 XV_HELP_DATA,        "mahjongg:credits",
  475.                 NULL);
  476.  
  477.     /* create seed item */
  478.  
  479.     board_num = xv_create(message_panel, PANEL_TEXT,
  480.                 PANEL_LABEL_STRING,    "Board Number : ",
  481.                 PANEL_VALUE,        "",
  482.                 PANEL_VALUE_DISPLAY_LENGTH,    7,
  483.                 XV_Y,            95,
  484.                 XV_X,            middle,
  485.                 PANEL_NOTIFY_PROC,    board_num_proc,
  486.                 XV_HELP_DATA,        "mahjongg:board_number",
  487.                 NULL);
  488.  
  489.     /* create control buttons */
  490.  
  491. #define ROW_FOR_BUTTONS        120
  492.     button_x = middle;
  493.     xv_create(message_panel, PANEL_BUTTON,
  494.                 XV_Y,            ROW_FOR_BUTTONS,
  495.                 XV_X,            button_x,
  496.                 PANEL_LABEL_STRING,    "HELP",
  497.                 (Use_colored_buttons
  498.                     ? PANEL_ITEM_COLOR : ATTR_NOP1),
  499.                             panel_color(CYAN),
  500.                 PANEL_NOTIFY_PROC,    help_proc,
  501.                 XV_HELP_DATA,        "mahjongg:help_button",
  502.                 NULL);
  503.  
  504.     xv_create(message_panel, PANEL_BUTTON,
  505.                 XV_Y,            ROW_FOR_BUTTONS,
  506.                 XV_X,            button_x += 55,
  507.                 PANEL_LABEL_STRING,    "AGAIN",
  508.                 (Use_colored_buttons
  509.                     ? PANEL_ITEM_COLOR : ATTR_NOP1),
  510.                             panel_color(YELLOW),
  511.                 PANEL_NOTIFY_PROC,    again_proc,
  512.                 XV_HELP_DATA,        "mahjongg:again_button",
  513.                 NULL);
  514.  
  515.     xv_create(message_panel, PANEL_BUTTON,
  516.                 XV_Y,            ROW_FOR_BUTTONS,
  517.                 XV_X,            button_x += 63,
  518.                 PANEL_LABEL_STRING,    "NEW",
  519.                 (Use_colored_buttons
  520.                     ? PANEL_ITEM_COLOR : ATTR_NOP1),
  521.                             panel_color(GREEN),
  522.                 PANEL_NOTIFY_PROC,    new_proc,
  523.                 XV_HELP_DATA,        "mahjongg:new_button",
  524.                 NULL);
  525.  
  526.     xv_create(message_panel, PANEL_BUTTON,
  527.                 XV_Y,            ROW_FOR_BUTTONS,
  528.                 XV_X,            button_x += 51,
  529.                 PANEL_LABEL_STRING,    "UNDO",
  530.                 (Use_colored_buttons
  531.                     ? PANEL_ITEM_COLOR : ATTR_NOP1),
  532.                             panel_color(MAGENTA),
  533.                 PANEL_NOTIFY_PROC,    undo_proc,
  534.                 XV_HELP_DATA,        "mahjongg:undo_button",
  535.                 NULL);
  536.  
  537.     xv_create(message_panel, PANEL_BUTTON,
  538.                 XV_Y,            ROW_FOR_BUTTONS,
  539.                 XV_X,            button_x += 61,
  540.                 PANEL_LABEL_STRING,    "QUIT",
  541.                 (Use_colored_buttons
  542.                     ? PANEL_ITEM_COLOR : ATTR_NOP1),
  543.                             panel_color(RED),
  544.                 PANEL_NOTIFY_PROC,    quit_proc,
  545.                 XV_HELP_DATA,        "mahjongg:quit_button",
  546.                 NULL);
  547.  
  548.     /* place concealed message */
  549.  
  550.     message = xv_create(message_panel, PANEL_MESSAGE,
  551.                 XV_Y,            150,
  552.                 XV_X,            middle,
  553.                 PANEL_LABEL_STRING,    "",
  554.                 XV_SHOW,        FALSE,
  555.                 XV_HELP_DATA,        "mahjongg:message_area",
  556.                 NULL);
  557.  
  558.     /* set up canvas for the play */
  559.  
  560.     play_canvas = xv_create(main_frame, CANVAS,
  561.             XV_HEIGHT,        PLAY_Y_MAX,
  562.             XV_WIDTH,        PLAY_X_MAX,
  563.             WIN_X,            0,
  564.             WIN_Y,            MESS_Y_MAX + BORDER,
  565.  
  566.             /* can be done here or on the canvas
  567.              * paint window */
  568.             (BandW ? ATTR_NOP1 : WIN_CMS),    mahjongg_canvas_cms,
  569.  
  570.             (Use_canvas_dynamic_cms ?
  571.                     WIN_DYNAMIC_VISUAL : ATTR_NOP1),
  572.                         TRUE,
  573.  
  574.             /*
  575.              * Switch background/foreground if B & W ; we also
  576.              * invert all the tiles (see above call to
  577.              * invert_tile_icon_mprs()), so that we
  578.              * get white tiles on a black background.  Otherwise
  579.              * we would get white tiles on a white background.
  580.              */
  581.             (Switch_bg_fg ? WIN_BACKGROUND_COLOR : ATTR_NOP1), 1,
  582.             (Switch_bg_fg ? WIN_FOREGROUND_COLOR : ATTR_NOP1), 0,
  583.  
  584.             CANVAS_REPAINT_PROC,    repaint_proc,
  585.             CANVAS_RETAINED,    TRUE,
  586.             XV_HELP_DATA,        "mahjongg:help",
  587.             NULL);
  588.  
  589.     Play_area = canvas_paint_window(play_canvas);
  590.  
  591.     init_cursors();
  592.  
  593.     set_mj_cursor(play_cursor);
  594.  
  595.     xv_set(Play_area,
  596.         WIN_EVENT_PROC,        play_event_proc,
  597.         WIN_CONSUME_EVENTS,
  598.                 WIN_NO_EVENTS,
  599.                 WIN_REPAINT,
  600.                 WIN_MOUSE_BUTTONS,
  601.                 WIN_ASCII_EVENTS,
  602.                     /* consume ASCII events only for the
  603.                      * purpose of ignoring them in the
  604.                      * event proc.  If you try to ignore
  605.                      * them via WIN_IGNORE_EVENTS, then
  606.                      * the events get re-directed to the
  607.                      * panel, which I didn't want. */
  608.                 NULL,
  609.         WIN_IGNORE_EVENTS,
  610.                 /* only want button-down mouse events */
  611.                 WIN_UP_EVENTS,
  612. #if JUST_A_COMMENT
  613.                 WIN_ASCII_EVENTS,
  614.                     /* if ASCII events are ignored by
  615.                      * the canvas, the events get sent
  616.                      * automatically (by XView) to the
  617.                      * panel.  For this program, I don't
  618.                      * think that effect is desired, so
  619.                      * instead of ignoring these events
  620.                      * here, I'll ignore them in the event
  621.                      * handler. */
  622. #endif
  623.                 NULL,
  624.         NULL);
  625.  
  626.     /* start main processing */
  627.  
  628.     xv_main_loop(main_frame);
  629.     exit(0);
  630. }
  631.  
  632. /*
  633.  * do_repaint is called from event.c
  634.  */
  635. void
  636. do_repaint()
  637. {
  638.     place_tiles(TRUE);
  639. }
  640.  
  641. /*
  642.  * With XView version 2.0, the repaint_proc always gets called either
  643.  * four (usually) or two times before the window first appears.
  644.  * Since this problem appears to be fixed under XView 3.0, and you
  645.  * only get one repaint at start-up time, I took out special code
  646.  * in this routine to avoid the extra repaints.  The extra repaints
  647.  * don't hurt anything--it's just a waste of CPU cycles. 
  648.  *     Note that because of dynamic link libraries, it wouldn't do to
  649.  * use ifdef's for this problem.  A single binary could run with either
  650.  * XView 2.0 or 3.0 libraries.
  651.  */
  652. void
  653. repaint_proc(canvas, play_area, repaint_area)
  654. Canvas canvas;
  655. Xv_Window play_area;        /* the canvas paint window */
  656. Rectlist *repaint_area;
  657. {
  658.     static int call_counter = 0;
  659.  
  660.     if (call_counter < 1) {
  661.     ++call_counter;
  662.     build_image(FALSE);
  663.     }
  664.  
  665.     place_tiles(TRUE);
  666. }
  667.  
  668.  
  669. /* die because of some UNIX error */
  670. void
  671. die(message, pperr)
  672. char *message;
  673. int pperr;
  674. {
  675.     fprintf(stderr, message);
  676.     if (pperr)
  677.     perror("mahjongg");
  678.     exit(1);
  679. }
  680.  
  681. void
  682. place_tiles(newboard)
  683. boolean        newboard;
  684. {
  685.     int     i;
  686.     int     j;
  687.     int     k;
  688.     int     x_loc;
  689.     int     y_loc;
  690.  
  691.     /* check if not new and destroy existing panel buttons */
  692.  
  693.     /* place tiles */
  694.  
  695.         /* row 1 level 1 */
  696.  
  697.     for(i = 0,
  698.         x_loc = COL2;
  699.         i < 12;
  700.         i++,
  701.         x_loc += W_BASE_TILE) 
  702.  
  703.         put_tile(board[i], x_loc, ROW1);
  704.  
  705.     /* row 2 level 1 */
  706.  
  707.     for(x_loc = COL4,
  708.         j = 0;
  709.         j < 8;
  710.         j++,
  711.         i++,
  712.         x_loc += W_BASE_TILE) 
  713.  
  714.         put_tile(board[i], x_loc, ROW2);
  715.  
  716.     /* row 3 level 1 */
  717.  
  718.     for(x_loc = COL3,
  719.         j = 0;
  720.         j < 10;
  721.         j++,
  722.         i++,
  723.         x_loc += W_BASE_TILE) 
  724.  
  725.         put_tile(board[i], x_loc, ROW3);
  726.  
  727.     /* row 4 1/2 level 1 */
  728.  
  729.     /* Left */
  730.  
  731.         put_tile(board[i], COL1, ROW4pt5);
  732.  
  733.         i++; /* increment tile counter */
  734.  
  735.     /* row 4 level 1 */
  736.  
  737.     for(x_loc = COL2,
  738.         j = 0;
  739.         j < 12;
  740.         j++,
  741.         i++,
  742.         x_loc += W_BASE_TILE) 
  743.  
  744.         put_tile(board[i], x_loc, ROW4);
  745.  
  746.     /* row 5 level 1 */
  747.  
  748.     for(x_loc = COL2,
  749.         j = 0;
  750.         j < 12;
  751.         j++,
  752.         i++,
  753.         x_loc += W_BASE_TILE) 
  754.  
  755.         put_tile(board[i], x_loc, ROW5);
  756.  
  757.     /* row 4 1/2 level 1 */
  758.  
  759.     /* Right */
  760.  
  761.         put_tile(board[i], COL14, ROW4pt5);
  762.  
  763.         i++; /* increment tile counter */
  764.  
  765.         put_tile(board[i], COL15, ROW4pt5);
  766.  
  767.         i++; /* increment tile counter */
  768.  
  769.     /* row 6 level 1 */
  770.  
  771.     for(x_loc = COL3,
  772.         j = 0;
  773.         j < 10;
  774.         j++,
  775.         i++,
  776.         x_loc += W_BASE_TILE) 
  777.  
  778.         put_tile(board[i], x_loc, ROW6);
  779.  
  780.     /* row 7 level 1 */
  781.  
  782.     for(x_loc = COL4,
  783.         j = 0;
  784.         j < 8;
  785.         j++,
  786.         i++,
  787.         x_loc += W_BASE_TILE) 
  788.  
  789.         put_tile(board[i], x_loc, ROW7);
  790.  
  791.         /* row 8 level 1 */
  792.  
  793.     for(j = 0,
  794.         x_loc = COL2;
  795.         j < 12;
  796.         j++,
  797.         i++,
  798.         x_loc += W_BASE_TILE) 
  799.  
  800.         put_tile(board[i], x_loc, ROW8);
  801.  
  802.     /* rows 1-6 level 2 */
  803.  
  804.     for(y_loc = ROW2 - B_TILE_SHADOW,
  805.         j = 0;
  806.         j < 6;
  807.         j++,
  808.         y_loc += H_BASE_TILE) 
  809.  
  810.         for(x_loc = COL5 - S_TILE_SHADOW,
  811.             k = 0;
  812.             k < 6;
  813.             i++,
  814.             k++,
  815.             x_loc += W_BASE_TILE) 
  816.  
  817.             put_tile(board[i], x_loc, y_loc);
  818.  
  819.     /* rows 1-4 level 3 */
  820.  
  821.     for(y_loc = ROW3 - (B_TILE_SHADOW * 2),
  822.         j = 0;
  823.         j < 4;
  824.         j++,
  825.         y_loc += H_BASE_TILE) 
  826.  
  827.         for(x_loc = COL6 - (S_TILE_SHADOW * 2),
  828.             k = 0;
  829.             k < 4;
  830.             i++,
  831.             k++,
  832.             x_loc += W_BASE_TILE) 
  833.  
  834.             put_tile(board[i], x_loc, y_loc);
  835.  
  836.     /* rows 1-2 level 4 */
  837.  
  838.     for(y_loc = ROW4 - (B_TILE_SHADOW * 3),
  839.         j = 0;
  840.         j < 2;
  841.         j++,
  842.         y_loc += H_BASE_TILE) 
  843.  
  844.         for(x_loc = COL7 - (S_TILE_SHADOW * 3),
  845.             k = 0;
  846.             k < 2;
  847.             i++,
  848.             k++,
  849.             x_loc += W_BASE_TILE) 
  850.  
  851.             put_tile(board[i], x_loc, y_loc);
  852.  
  853.     /* Cap tile */
  854.  
  855.         put_tile(board[i],
  856.                 COL7pt5 - (S_TILE_SHADOW * 4),
  857.                 ROW4pt5 - (B_TILE_SHADOW * 4));
  858.  
  859.     /* need this especially for a screen refresh */
  860.     if (selected[0].in_preview_mode && ! selected[0].tileptr->removed)
  861.     begin_preview(&selected[0]);
  862.     if (selected[1].in_preview_mode && ! selected[1].tileptr->removed)
  863.     begin_preview(&selected[1]);
  864.  
  865.     /*
  866.      * The panel_msg() call below shouldn't be done when just refreshing
  867.      * the screen.  It should only be done when this routine
  868.      * is called after a build_image() call.  This would happen when the
  869.      * program first starts up, and after an "AGAIN" or "NEW" selection.
  870.      */
  871.     if (Clear_msg) {
  872.     /* clear stand_by message  and release input mask */
  873.  
  874.        panel_msg((char *)0, play_cursor_si, FALSE);
  875.        Clear_msg = FALSE;
  876.     }
  877. }
  878.  
  879. void
  880. build_image(oldimage)
  881. boolean oldimage;
  882. {
  883.     int i;
  884.     int j;
  885.     char seed_text[80];
  886.     Tile_val tmp_pool[144];
  887.     int tmp_tiles_left;
  888.     int pos;
  889.  
  890.     /* initialize selected structures */
  891.  
  892.         selected[0].in_preview_mode = FALSE;
  893.         selected[1].in_preview_mode = FALSE;
  894.         undo_count          = -1;
  895.  
  896.         xv_set(message, XV_SHOW, FALSE, 0);
  897.  
  898.     if (Use_num_server_images) {
  899.         xv_set(TL_hundred, 
  900.             PANEL_LABEL_IMAGE,    Num_icon_si[1],
  901.             XV_SHOW,        TRUE,
  902.             0);
  903.         xv_set(TL_ten, 
  904.             PANEL_LABEL_IMAGE,    Num_icon_si[4],
  905.             XV_SHOW,        TRUE,
  906.             0);
  907.         xv_set(TL_one, 
  908.             PANEL_LABEL_IMAGE,    Num_icon_si[4],
  909.             XV_SHOW,        TRUE,
  910.             0);
  911.     }
  912.     else {
  913.         xv_set(TL_hundred, 
  914.             PANEL_LABEL_IMAGE,    Num_icon_mpr[1],
  915.             XV_SHOW,        TRUE,
  916.             0);
  917.         xv_set(TL_ten, 
  918.             PANEL_LABEL_IMAGE,    Num_icon_mpr[4],
  919.             XV_SHOW,        TRUE,
  920.             0);
  921.         xv_set(TL_one, 
  922.             PANEL_LABEL_IMAGE,    Num_icon_mpr[4],
  923.             0);
  924.     }
  925.  
  926.     /* display current seed in text item */
  927.  
  928.         sprintf(seed_text, "%d", seed);
  929.     xv_set(board_num, PANEL_VALUE, seed_text, 0);
  930.  
  931.     /* show stand_by message while building image  and grab all input */
  932.  
  933.     panel_msg("Building board. Please wait.", wait_cursor_si, FALSE);
  934.     Clear_msg = TRUE;
  935.  
  936.     /* initialize random number counter */
  937.  
  938.     (void) srandom(seed);
  939.  
  940.     tile_count = 144;
  941.  
  942.     /* initialize  tmp_pool */
  943.         for(j = 0; j < 136; j++) tmp_pool[j] = j/4; /* tiles * 4 */
  944.         for(j=136; j<144; j++) tmp_pool[j] = j- 102; /* flowers & seasons */
  945.                                                    /* 136 --> 34 */
  946.                                                    /* 143 --> 41 */
  947.         tmp_tiles_left = 144;
  948.  
  949.  
  950.     if (board[0] == NULL) {
  951.         /* intialize array */
  952.         for (i = 0; i < 144; i++) {
  953.         board[i] = &board_tile[i];
  954.         }
  955.     }
  956.  
  957.     /* assign values to each location. Board is built from upper left *
  958.      * to lower right, bottom to top. Exception are left tile for row *
  959.      * 4pt5 is before rows 4 and 5, and right tiles for row 4.5 are   *
  960.      * after rows 4 and 5                                             */
  961.  
  962.     for (j = 0; j < 144; j++) {
  963.  
  964.         if (!oldimage) { /* not repeating last board */
  965.  
  966.            /* Shuffle/pick tile */
  967.  
  968.                pos = RANDOM(tmp_tiles_left);
  969.  
  970.                i= tmp_pool[pos];
  971.  
  972.                for( ; pos < tmp_tiles_left; pos++)
  973.             tmp_pool[pos] = tmp_pool[pos+1];
  974.  
  975.                tmp_tiles_left--;
  976.  
  977.         /* all flowers and all seasons */
  978.  
  979.         board[j]->value = (i >= 34) ? ((i >= 38) ? 35 : 34) : i;
  980.         board[j]->image = i;
  981.         }
  982.     /* establish default values */
  983.  
  984.         board[j]->left_free     = FALSE;
  985.         board[j]->right_free    = FALSE;
  986.         board[j]->top_free      = TRUE;
  987.         board[j]->top_covered    = FALSE;
  988.         board[j]->left_next[0]  = j - 1;
  989.         board[j]->left_next[1]  = DONT_CARE;
  990.         board[j]->right_next[0] = j + 1;
  991.         board[j]->right_next[1] = DONT_CARE;
  992.         board[j]->covered[0] = DONT_CARE;
  993.         board[j]->covered[1] = DONT_CARE;
  994.         board[j]->covered[2] = DONT_CARE;
  995.         board[j]->covered[3] = DONT_CARE;
  996.         board[j]->removed       = FALSE;
  997.  
  998.     /* setup special cases */
  999.  
  1000.         switch (j) {
  1001.         case 139:
  1002.         case 141: 
  1003.             board[j]->top_free = FALSE;
  1004.         case 0:
  1005.         case 12:
  1006.         case 20:
  1007.         case 30:
  1008.         case 57:
  1009.         case 67:
  1010.         case 75:
  1011.         case 87:
  1012.         case 93:
  1013.         case 99:
  1014.         case 105:
  1015.         case 111:
  1016.         case 117:
  1017.         case 123:
  1018.         case 127:
  1019.         case 131:
  1020.         case 135:
  1021.             board[j]->left_free = TRUE;
  1022.             board[j]->left_next[0] = DONT_CARE;
  1023.             break;
  1024.         case 140:
  1025.         case 142:
  1026.             board[j]->top_free = FALSE;
  1027.         case 11:
  1028.         case 19:
  1029.         case 29:
  1030.         case 56:
  1031.         case 66:
  1032.         case 74:
  1033.         case 86:
  1034.         case 92:
  1035.         case 98:
  1036.         case 104:
  1037.         case 110:
  1038.         case 116:
  1039.         case 122:
  1040.         case 126:
  1041.         case 130:
  1042.         case 134:
  1043.         case 138:
  1044.             board[j]->right_free = TRUE;
  1045.             board[j]->right_next[0] = DONT_CARE;
  1046.             break;
  1047.         case 143:
  1048.             board[j]->right_free = TRUE;
  1049.             board[j]->left_next[0] = DONT_CARE;
  1050.             board[j]->left_free = TRUE;
  1051.             board[j]->right_next[0] = DONT_CARE;
  1052.             board[j]->covered[0] = 139;
  1053.             board[j]->covered[1] = 140;
  1054.             board[j]->covered[2] = 141;
  1055.             board[j]->covered[3] = 142;
  1056.             break;
  1057.         case 42:
  1058.             board[j]->right_next[0] = 55;
  1059.             break;
  1060.         case 43:
  1061.             board[j]->left_next[0] = 30;
  1062.             break;
  1063.         case 55:
  1064.             board[j]->left_next[1] = 42;
  1065.             break;
  1066.         }
  1067.             
  1068.     }
  1069.  
  1070.     /* special case (did not fit in above) */
  1071.  
  1072.     board[30]->right_next[1] = 43;
  1073.  
  1074.     /* set top_free flags  and covered pointers */
  1075.  
  1076.     for(i = 87, j = 13; i < 143; i++, j++) {
  1077.         board[i]->covered[0] = j;
  1078.         board[j]->top_free = FALSE;
  1079.         board[j]->top_covered = TRUE;
  1080.         switch(j) {
  1081.             case 97:
  1082.             case 103:
  1083.             case 109:
  1084.             case 129:
  1085.                  j += 2;
  1086.                  break;
  1087.             case 18:
  1088.             case 64:
  1089.                  j += 3;
  1090.                  break;
  1091.             case 27:
  1092.             case 39:
  1093.                  j += 6;
  1094.                  break;
  1095.             case 51:
  1096.                  j += 7;
  1097.                  break;
  1098.             case 73:
  1099.                  j += 20;
  1100.                  break;
  1101.             case 115:
  1102.                  j += 12;
  1103.                  break;
  1104.         }
  1105.     }
  1106. }
  1107.  
  1108. setup_cms()
  1109. {
  1110.     mahjongg_icon_cms = (Cms) xv_create(NULL, CMS,
  1111.         CMS_SIZE,        NUM_COLORS,
  1112.         CMS_NAME,        "mahjongg_icon_cms",
  1113.         CMS_NAMED_COLORS,    Mahjongg_color_list,
  1114.                     NULL,
  1115.         NULL);
  1116.  
  1117.     if (Use_panel_control_cms)
  1118.     mahjongg_panel_cms = (Cms) xv_create(NULL, CMS,
  1119.         CMS_CONTROL_CMS,    TRUE,
  1120.         CMS_SIZE,        CMS_CONTROL_COLORS + NUM_COLORS + 1,
  1121.         CMS_NAME,        "mahjongg_panel_cms",
  1122.         CMS_NAMED_COLORS,    Mahjongg_color_list,
  1123.                     "black", /* last is foreground color */
  1124.                     NULL,
  1125.         NULL);
  1126.     else
  1127.     mahjongg_panel_cms = (Cms) xv_create(NULL, CMS,
  1128.         CMS_SIZE,        NUM_COLORS,
  1129.         CMS_NAME,        "mahjongg_panel_cms",
  1130.         CMS_NAMED_COLORS,    Mahjongg_color_list, NULL,
  1131.         NULL);
  1132.  
  1133.     mahjongg_canvas_cms = NULL;
  1134.     if (Use_canvas_dynamic_cms) {
  1135.     mahjongg_canvas_cms = (Cms) create_aligned_cms(NUM_COLORS);
  1136.     if (mahjongg_canvas_cms == NULL) {
  1137.         fprintf(stderr, "Error, couldn't create dynamic colormap\n");
  1138.         fprintf(stderr, "Trying regular colormap...\n");
  1139.         Use_canvas_dynamic_cms = FALSE;
  1140.     }
  1141.     else {
  1142.         /* name the cms and set the colors */
  1143.         xv_set(mahjongg_canvas_cms,
  1144.         CMS_NAME,        "mahjongg_canvas_cms",
  1145.         CMS_NAMED_COLORS,    Mahjongg_color_list, NULL,
  1146.         NULL);
  1147.     }
  1148.     }
  1149.  
  1150.     if (mahjongg_canvas_cms == NULL) {
  1151.     mahjongg_canvas_cms = (Cms) xv_create(NULL, CMS,
  1152.         (Use_canvas_control_cms ? CMS_CONTROL_CMS : ATTR_NOP1),    TRUE,
  1153.         CMS_SIZE,        Use_canvas_control_cms ?
  1154.                            CMS_CONTROL_COLORS + NUM_COLORS :
  1155.                         NUM_COLORS,
  1156.         CMS_NAME,        "mahjongg_canvas_cms",
  1157.         CMS_NAMED_COLORS,    Mahjongg_color_list,
  1158.                     NULL,
  1159.         NULL);
  1160.     }
  1161. }
  1162.  
  1163. put_tile(tileptr, x_loc, y_loc)
  1164. Tile *tileptr;
  1165. int x_loc;
  1166. int y_loc;
  1167. {
  1168.     tileptr->x_loc = x_loc;
  1169.     tileptr->y_loc = y_loc;
  1170.  
  1171.     if (tileptr->removed)
  1172.     return;
  1173.  
  1174.     if (! tileptr->top_covered)
  1175.     if (Use_tile_server_images)
  1176.         pw_write(Play_area, x_loc, y_loc, 64, 64,
  1177.             PIX_SRC, Tile_icon_si[tileptr->image], 0, 0);
  1178.     else
  1179.         pw_write(Play_area, x_loc, y_loc, 64, 64,
  1180.             PIX_SRC, Tile_icon_mpr[tileptr->image], 0, 0);
  1181.     else
  1182.     if (Use_tile_server_images)
  1183.         pw_write(Play_area, x_loc, y_loc, 64, 64,
  1184.             PIX_SRC, Tile_icon_si[BLANK_I], 0, 0);
  1185.     else
  1186.         pw_write(Play_area, x_loc, y_loc, 64, 64,
  1187.             PIX_SRC, Tile_icon_mpr[BLANK_I], 0, 0);
  1188. }
  1189.  
  1190. invert_pixrect(pr)
  1191. Pixrect *pr;
  1192. {
  1193.     if (PIXRECT_IMAGE_DEPTH(pr) <= 1)
  1194.     invert_mono_image( PIXRECT_IMAGE_DATA_PTR(pr),
  1195.             PIXRECT_IMAGE_SIZE(pr) );
  1196.     else
  1197.     invert_color_image( PIXRECT_IMAGE_DATA_PTR(pr),
  1198.             PIXRECT_IMAGE_SIZE(pr) );
  1199. }
  1200.  
  1201. invert_mono_image(p, buflen)
  1202. unsigned char *p;
  1203. int buflen;
  1204. {
  1205.     int i;
  1206.  
  1207.     for (i = 0; i < buflen; i++, p++)
  1208.     *p = ~(*p);
  1209. }
  1210.  
  1211. invert_color_image(p, buflen)
  1212. unsigned char *p;
  1213. int buflen;
  1214. {
  1215.     int i, j;
  1216.     static unsigned long *colors = NULL;
  1217.  
  1218.     if (colors == NULL) {
  1219.     colors = (unsigned long *) xv_get(mahjongg_canvas_cms, CMS_INDEX_TABLE);
  1220.     }
  1221.     if (Use_canvas_control_cms) {
  1222.     for (i = 0; i < buflen; i++, p++) {
  1223.         /* will have a color in the range 4-11; and want to invert in
  1224.          * that range only (i.e., 4 inverts to 11, 5 inverts to 10, ...
  1225.          */
  1226.         *p = (7 + CMS_CONTROL_COLORS) - (*p - CMS_CONTROL_COLORS);
  1227.     }
  1228.     }
  1229.     else {
  1230.     for (i = 0; i < buflen; i++, p++)
  1231.         *p = 7 - *p;
  1232.     }
  1233. }
  1234.  
  1235. shift_pixrect_colors(pr)
  1236. Pixrect *pr;
  1237. {
  1238.     if (PIXRECT_IMAGE_DEPTH(pr) <= 1)
  1239.     return;
  1240.  
  1241.     shift_image_colors( PIXRECT_IMAGE_DATA_PTR(pr),
  1242.             PIXRECT_IMAGE_SIZE(pr) );
  1243. }
  1244.  
  1245. /*
  1246.  * this routine assumes the colors are already in the proper range
  1247.  */
  1248. shift_image_colors(p, buflen)
  1249. unsigned char *p;
  1250. int buflen;
  1251. {
  1252.     int i;
  1253.  
  1254.     for (i = 0; i < buflen; i++, p++)
  1255.     *p += CMS_CONTROL_COLORS;
  1256. }
  1257.  
  1258. get_cms_inverse_table(cms)
  1259. Cms cms;
  1260. {
  1261.     unsigned long *colors;
  1262.     int i;
  1263.     extern unsigned char Cms_inverse_table[];
  1264.     int cms_size;
  1265.  
  1266.     colors = (unsigned long *) xv_get(cms, CMS_INDEX_TABLE);
  1267.     cms_size = xv_get(cms, CMS_SIZE);
  1268.  
  1269.     for (i = 0; i < cms_size; i++)
  1270.     Cms_inverse_table[colors[i]] = i;
  1271. }
  1272.  
  1273. convert_physical_to_logical_colors(p, buflen)
  1274. unsigned char *p;
  1275. int buflen;
  1276. {
  1277.     int i;
  1278.     extern unsigned char Cms_inverse_table[];
  1279.  
  1280.     for (i = 0; i < buflen; i++, p++)
  1281.     *p = Cms_inverse_table[*p];
  1282. }
  1283.  
  1284. convert_physical_to_logical_colors_pixrect(p)
  1285. Pixrect *p;
  1286. {
  1287.     convert_physical_to_logical_colors(
  1288.         PIXRECT_IMAGE_DATA_PTR(p),
  1289.         PIXRECT_IMAGE_SIZE(p));
  1290. }
  1291.  
  1292. init_num_icon_mprs()
  1293. {
  1294.     if (BandW) {
  1295.     Num_icon_mpr[0] = &NUM0;
  1296.     Num_icon_mpr[1] = &NUM1;
  1297.     Num_icon_mpr[2] = &NUM2;
  1298.     Num_icon_mpr[3] = &NUM3;
  1299.     Num_icon_mpr[4] = &NUM4;
  1300.     Num_icon_mpr[5] = &NUM5;
  1301.     Num_icon_mpr[6] = &NUM6;
  1302.     Num_icon_mpr[7] = &NUM7;
  1303.     Num_icon_mpr[8] = &NUM8;
  1304.     Num_icon_mpr[9] = &NUM9;
  1305.     }
  1306.     else {
  1307.     Num_icon_mpr[0] = &cNUM0;
  1308.     Num_icon_mpr[1] = &cNUM1;
  1309.     Num_icon_mpr[2] = &cNUM2;
  1310.     Num_icon_mpr[3] = &cNUM3;
  1311.     Num_icon_mpr[4] = &cNUM4;
  1312.     Num_icon_mpr[5] = &cNUM5;
  1313.     Num_icon_mpr[6] = &cNUM6;
  1314.     Num_icon_mpr[7] = &cNUM7;
  1315.     Num_icon_mpr[8] = &cNUM8;
  1316.     Num_icon_mpr[9] = &cNUM9;
  1317.     }
  1318. }
  1319.  
  1320. shift_num_icon_mprs()
  1321. {
  1322.     int i;
  1323.  
  1324.     for (i = 0; i < NUM_ICON_COUNT; i++)
  1325.     shift_pixrect_colors(Num_icon_mpr[i]);
  1326. }
  1327.  
  1328. init_num_icon_server_images()
  1329. {
  1330.     int i;
  1331.  
  1332.     if (BandW) {
  1333.     for (i = 0; i < NUM_ICON_COUNT; i++) {
  1334.         Num_icon_si[i] = (Server_image) xv_create(NULL, SERVER_IMAGE,
  1335.             XV_WIDTH,        64,
  1336.             XV_HEIGHT,        64,
  1337.             SERVER_IMAGE_DEPTH,    1,
  1338.             SERVER_IMAGE_BITS,
  1339.                 PIXRECT_IMAGE_DATA_PTR(Num_icon_mpr[i]),
  1340.             NULL);
  1341.     }
  1342.     }
  1343.     else {
  1344.     for (i = 0; i < NUM_ICON_COUNT; i++) {
  1345.         Num_icon_si[i] = (Server_image) xv_create(NULL, SERVER_IMAGE,
  1346.             XV_WIDTH,        64,
  1347.             XV_HEIGHT,        64,
  1348.             SERVER_IMAGE_DEPTH,    8,
  1349.             SERVER_IMAGE_COLORMAP,    "mahjongg_panel_cms",
  1350.             SERVER_IMAGE_BITS,
  1351.                 PIXRECT_IMAGE_DATA_PTR(Num_icon_mpr[i]),
  1352.             NULL);
  1353.     }
  1354.     }
  1355. }
  1356.  
  1357. init_tile_icon_mprs()
  1358. {
  1359.     if (BandW) {
  1360.     Tile_icon_mpr[BAM1_I] = &BAM1;
  1361.     Tile_icon_mpr[BAM2_I] = &BAM2;
  1362.     Tile_icon_mpr[BAM3_I] = &BAM3;
  1363.     Tile_icon_mpr[BAM4_I] = &BAM4;
  1364.     Tile_icon_mpr[BAM5_I] = &BAM5;
  1365.     Tile_icon_mpr[BAM6_I] = &BAM6;
  1366.     Tile_icon_mpr[BAM7_I] = &BAM7;
  1367.     Tile_icon_mpr[BAM8_I] = &BAM8;
  1368.     Tile_icon_mpr[BAM9_I] = &BAM9;
  1369.  
  1370.     Tile_icon_mpr[DOT1_I] = &DOT1;
  1371.     Tile_icon_mpr[DOT2_I] = &DOT2;
  1372.     Tile_icon_mpr[DOT3_I] = &DOT3;
  1373.     Tile_icon_mpr[DOT4_I] = &DOT4;
  1374.     Tile_icon_mpr[DOT5_I] = &DOT5;
  1375.     Tile_icon_mpr[DOT6_I] = &DOT6;
  1376.     Tile_icon_mpr[DOT7_I] = &DOT7;
  1377.     Tile_icon_mpr[DOT8_I] = &DOT8;
  1378.     Tile_icon_mpr[DOT9_I] = &DOT9;
  1379.  
  1380.     Tile_icon_mpr[CHA1_I] = &CHA1;
  1381.     Tile_icon_mpr[CHA2_I] = &CHA2;
  1382.     Tile_icon_mpr[CHA3_I] = &CHA3;
  1383.     Tile_icon_mpr[CHA4_I] = &CHA4;
  1384.     Tile_icon_mpr[CHA5_I] = &CHA5;
  1385.     Tile_icon_mpr[CHA6_I] = &CHA6;
  1386.     Tile_icon_mpr[CHA7_I] = &CHA7;
  1387.     Tile_icon_mpr[CHA8_I] = &CHA8;
  1388.     Tile_icon_mpr[CHA9_I] = &CHA9;
  1389.  
  1390.     Tile_icon_mpr[EAST_I] = &EAST;
  1391.     Tile_icon_mpr[WEST_I] = &WEST;
  1392.     Tile_icon_mpr[SOUT_I] = &SOUT;
  1393.     Tile_icon_mpr[NORT_I] = &NORT;
  1394.  
  1395.     Tile_icon_mpr[GRED_I] = &GRED;
  1396.     Tile_icon_mpr[REDD_I] = &REDD;
  1397.     Tile_icon_mpr[WHTD_I] = &WHTD;
  1398.  
  1399.     Tile_icon_mpr[AUT_I] = &AUT;
  1400.     Tile_icon_mpr[SPR_I] = &SPR;
  1401.     Tile_icon_mpr[SUM_I] = &SUM;
  1402.     Tile_icon_mpr[WIN_I] = &WIN;
  1403.  
  1404.     Tile_icon_mpr[BAM_I] = &BAM;
  1405.     Tile_icon_mpr[MUM_I] = &MUM;
  1406.     Tile_icon_mpr[ORC_I] = &ORC;
  1407.     Tile_icon_mpr[PLM_I] = &PLM;
  1408.  
  1409.     Tile_icon_mpr[BLANK_I] = &BLANK;
  1410.     }
  1411.     else {
  1412.     Tile_icon_mpr[BAM1_I] = &cBAM1;
  1413.     Tile_icon_mpr[BAM2_I] = &cBAM2;
  1414.     Tile_icon_mpr[BAM3_I] = &cBAM3;
  1415.     Tile_icon_mpr[BAM4_I] = &cBAM4;
  1416.     Tile_icon_mpr[BAM5_I] = &cBAM5;
  1417.     Tile_icon_mpr[BAM6_I] = &cBAM6;
  1418.     Tile_icon_mpr[BAM7_I] = &cBAM7;
  1419.     Tile_icon_mpr[BAM8_I] = &cBAM8;
  1420.     Tile_icon_mpr[BAM9_I] = &cBAM9;
  1421.  
  1422.     Tile_icon_mpr[DOT1_I] = &cDOT1;
  1423.     Tile_icon_mpr[DOT2_I] = &cDOT2;
  1424.     Tile_icon_mpr[DOT3_I] = &cDOT3;
  1425.     Tile_icon_mpr[DOT4_I] = &cDOT4;
  1426.     Tile_icon_mpr[DOT5_I] = &cDOT5;
  1427.     Tile_icon_mpr[DOT6_I] = &cDOT6;
  1428.     Tile_icon_mpr[DOT7_I] = &cDOT7;
  1429.     Tile_icon_mpr[DOT8_I] = &cDOT8;
  1430.     Tile_icon_mpr[DOT9_I] = &cDOT9;
  1431.  
  1432.     Tile_icon_mpr[CHA1_I] = &cCHA1;
  1433.     Tile_icon_mpr[CHA2_I] = &cCHA2;
  1434.     Tile_icon_mpr[CHA3_I] = &cCHA3;
  1435.     Tile_icon_mpr[CHA4_I] = &cCHA4;
  1436.     Tile_icon_mpr[CHA5_I] = &cCHA5;
  1437.     Tile_icon_mpr[CHA6_I] = &cCHA6;
  1438.     Tile_icon_mpr[CHA7_I] = &cCHA7;
  1439.     Tile_icon_mpr[CHA8_I] = &cCHA8;
  1440.     Tile_icon_mpr[CHA9_I] = &cCHA9;
  1441.  
  1442.     Tile_icon_mpr[EAST_I] = &cEAST;
  1443.     Tile_icon_mpr[WEST_I] = &cWEST;
  1444.     Tile_icon_mpr[SOUT_I] = &cSOUT;
  1445.     Tile_icon_mpr[NORT_I] = &cNORT;
  1446.  
  1447.     Tile_icon_mpr[GRED_I] = &cGRED;
  1448.     Tile_icon_mpr[REDD_I] = &cREDD;
  1449.     Tile_icon_mpr[WHTD_I] = &cWHTD;
  1450.  
  1451.     Tile_icon_mpr[AUT_I] = &cAUT;
  1452.     Tile_icon_mpr[SPR_I] = &cSPR;
  1453.     Tile_icon_mpr[SUM_I] = &cSUM;
  1454.     Tile_icon_mpr[WIN_I] = &cWIN;
  1455.  
  1456.     Tile_icon_mpr[BAM_I] = &cBAM;
  1457.     Tile_icon_mpr[MUM_I] = &cMUM;
  1458.     Tile_icon_mpr[ORC_I] = &cORC;
  1459.     Tile_icon_mpr[PLM_I] = &cPLM;
  1460.  
  1461.     Tile_icon_mpr[BLANK_I] = &cBLANK;
  1462.     }
  1463. }
  1464.  
  1465. invert_tile_icon_mprs()
  1466. {
  1467.     int i;
  1468.  
  1469.     for (i = 0; i < TILE_ICON_COUNT; i++)
  1470.     invert_pixrect(Tile_icon_mpr[i]);
  1471. }
  1472.  
  1473. shift_tile_icon_mprs()
  1474. {
  1475.     int i;
  1476.  
  1477.     for (i = 0; i < TILE_ICON_COUNT; i++)
  1478.     shift_pixrect_colors(Tile_icon_mpr[i]);
  1479. }
  1480.  
  1481. init_tile_icon_server_images()
  1482. {
  1483.     int i;
  1484.  
  1485.     if (BandW) {
  1486.     for (i = 0; i < TILE_ICON_COUNT; i++) {
  1487.         Tile_icon_si[i] = (Server_image) xv_create(NULL, SERVER_IMAGE,
  1488.             XV_WIDTH,        64,
  1489.             XV_HEIGHT,        64,
  1490.             SERVER_IMAGE_DEPTH,    1,
  1491.             SERVER_IMAGE_BITS,
  1492.                 PIXRECT_IMAGE_DATA_PTR(Tile_icon_mpr[i]),
  1493.             NULL);
  1494.     }
  1495.     }
  1496.     else {
  1497.     for (i = 0; i < TILE_ICON_COUNT; i++) {
  1498.         Tile_icon_si[i] = (Server_image) xv_create(NULL, SERVER_IMAGE,
  1499.             XV_WIDTH,        64,
  1500.             XV_HEIGHT,        64,
  1501.             SERVER_IMAGE_DEPTH,    8,
  1502.             SERVER_IMAGE_COLORMAP,    "mahjongg_canvas_cms",
  1503.             SERVER_IMAGE_BITS,
  1504.                 PIXRECT_IMAGE_DATA_PTR(Tile_icon_mpr[i]),
  1505.             NULL);
  1506.     }
  1507.     }
  1508. }
  1509.  
  1510. /*
  1511.  * Given an x,y coordinate, find the tile which has been selected, if any.
  1512.  * Could set up a linked list that keeps track of which tiles are free,
  1513.  * and search only that.  But it's even cheaper (less memory) to just
  1514.  * use the information that's already in the Tile data structure to determine
  1515.  * what tiles to look at.  Given the linked list manipulation, etc., it's
  1516.  * questionable whether or not that would be worth the trouble.
  1517.  */
  1518. find_tile(x, y)
  1519. int x, y;
  1520. {
  1521.    int i;
  1522.  
  1523.    for (i = 143; i >= 0; i--) {
  1524.     if (
  1525.         ! (board[i]->removed)
  1526.         &&
  1527. #if JUST_A_COMMENT
  1528.     /*
  1529.      * if this code is used, then some strange effects will be seen:
  1530.      * a tile which really isn't being pointed at can be selected, because
  1531.      * of the fact that we're only looking at tiles which have the left
  1532.      * or right free
  1533.      */
  1534.           (
  1535.         board[i]->left_free
  1536.         ||
  1537.         board[i]->right_free
  1538.           )
  1539.         &&
  1540. #endif
  1541.         board[i]->x_loc <= x
  1542.         &&
  1543.         board[i]->y_loc <= y
  1544.         &&
  1545.         x <= board[i]->x_loc + 64
  1546.         &&
  1547.         y <= board[i]->y_loc + 64
  1548.         )
  1549.  
  1550.         return(i);
  1551.     }
  1552.  
  1553.     return(-1);
  1554. }
  1555.  
  1556. print_help()
  1557. {
  1558. #define prt(s)    fprintf(stderr, s)
  1559.     prt(Usage_msg);
  1560.     prt("-b\tforce black and white mode (bg/fg bi-color)\n");
  1561.     prt("-c\tforce color mode\n");
  1562.     prt("-n #\tspecify seed number\n");
  1563.     prt("-P\tconfigure control panel to use normal background color\n");
  1564.     prt("-PB\tlike -P, but with uniformly colored buttons\n");
  1565.     prt("-B\tlike -b, but uses black (or bg color) background\n");
  1566.     prt("\t-B and -BB below only work when used with a color display\n");
  1567.     prt("-BB\tlike -B, but with black (or fg color) tiles\n");
  1568.     prt("-C\tconfigure game area to use normal background color\n");
  1569.     prt("    warning: -C forces the -D option described below\n");
  1570.     prt("-D\tdon't use direct color manipulation for tile highlighting\n");
  1571.     prt("\t-D minimizes usage of color map entries but is slower\n");
  1572.     prt("-N\tuse pixrects instead of server images for panel icons\n");
  1573.     prt("\t-N not recommended, but reduces server memory usage\n");
  1574.     prt("-T\tuse pixrects instead of server images for tile icons\n");
  1575.     prt("\t-T reduces server memory usage but slows screen updates\n");
  1576.  
  1577.     prt("-E\tenable use of error bells\n");
  1578.  
  1579.     prt("==========================================================\n");
  1580.     if (isatty(fileno(stdin))
  1581.         && isatty(fileno(stdout)) && isatty(fileno(stderr))) {
  1582.     /* don't want to do this if they re-direct output to a file */
  1583.     char buf[80];
  1584.     fputs("Enter Return to see XView help, or 'q' and Return to quit: ",
  1585.             stdout);
  1586.     fgets(buf, sizeof(buf), stdin);
  1587.     if (buf[0] == 'q')
  1588.         exit(0);
  1589.     }
  1590. }
  1591.  
  1592. init_cursors()
  1593. {
  1594.     wait_cursor_si = (Server_image) xv_create(XV_NULL, SERVER_IMAGE,
  1595.         XV_WIDTH,        16,
  1596.         XV_HEIGHT,        16,
  1597.         SERVER_IMAGE_BITS,    wait_image,
  1598.         NULL);
  1599.     confirm_cursor_si = (Server_image) xv_create(XV_NULL, SERVER_IMAGE,
  1600.         XV_WIDTH,        16,
  1601.         XV_HEIGHT,        16,
  1602.         SERVER_IMAGE_BITS,    confirm_image,
  1603.         NULL);
  1604.  
  1605.     stick_cursor_si = (Server_image) xv_create(XV_NULL, SERVER_IMAGE,
  1606.         XV_WIDTH,        16,
  1607.         XV_HEIGHT,        16,
  1608.         SERVER_IMAGE_BITS,    stick_image,
  1609.         NULL);
  1610.  
  1611.     play_cursor_si = stick_cursor_si;
  1612.  
  1613.     play_cursor = (Xv_Cursor) xv_create(XV_NULL, CURSOR,
  1614.         CURSOR_IMAGE,    play_cursor_si,
  1615.         CURSOR_XHOT,    0,
  1616.         CURSOR_YHOT,    0,
  1617.         CURSOR_OP,    PIX_SRC ^ PIX_DST,
  1618.             /* XView interprets this CURSOR_OP as being
  1619.              * the CURSOR_IMAGE with a mask behind it and
  1620.              * also around it, colored in the background
  1621.              * color; the cursor is opaque */
  1622.         NULL);
  1623.  
  1624.     if (! BandW) {
  1625.     Xv_singlecolor bg, fg;
  1626.  
  1627.     bg.red = 0, bg.green = 0, bg.blue = 0;
  1628.     fg.red = 0, fg.green = 255, fg.blue = 0;
  1629.  
  1630.     xv_set(play_cursor,
  1631.         CURSOR_BACKGROUND_COLOR,    &bg,
  1632.         CURSOR_FOREGROUND_COLOR,    &fg,
  1633.         NULL);
  1634.     }
  1635. }
  1636.  
  1637. /*
  1638.  * Figure out the depth of the display.  Kind of weird code, but it
  1639.  * works.  Create a frame and then destroy it, just in order to
  1640.  * determine the depth.  The reason why we can't just do an xv_create()
  1641.  * of the main_frame, followed by an xv_set() of the colormap segment,
  1642.  * is that the colormap segment must be set at create time or else
  1643.  * the icon doesn't appear right.
  1644.  */
  1645. get_display_depth()
  1646. {
  1647.     Frame frame;
  1648.     int depth;
  1649.  
  1650.     frame = xv_create(XV_NULL, FRAME, NULL);
  1651.  
  1652.     depth = xv_get(frame, WIN_DEPTH);
  1653.  
  1654.     xv_destroy(frame);
  1655.  
  1656.     return(depth);
  1657. }
  1658.  
  1659. set_mj_cursor(play_cursor)
  1660. Xv_Cursor play_cursor;
  1661. {
  1662.     xv_set(Play_area, WIN_CURSOR, play_cursor, NULL);
  1663.     xv_set(message_panel, WIN_CURSOR, play_cursor, NULL);
  1664.     xv_set(main_frame, WIN_CURSOR, play_cursor, NULL);
  1665. }
  1666.  
  1667. /*
  1668.  * Create a cms that is "properly aligned".  For 8 colors, a properly
  1669.  * aligned cms is one that begins at a multiple of 8 (0, 8, 16, ...).
  1670.  * This kind of cms is needed when you want to change the plane mask
  1671.  * in order to restrict bit manipulations (raster-ops) to only
  1672.  * certain planes.  For this reason, the number of colors would ordinarily
  1673.  * be a power of 2.
  1674.  */
  1675. Cms
  1676. create_aligned_cms(num_colors)
  1677. int num_colors;
  1678. {
  1679. #define MAX_TRIES    3
  1680.     unsigned long *cms_index_table;
  1681.     Cms cms;
  1682.     Cms dummy_cms;
  1683.     Cms destroy_list[MAX_TRIES * 2];    /* will hold on to at most 2 cms's
  1684.                      * per try; we hold on to cms's so
  1685.                      * that the colorcells in those cms's
  1686.                      * don't get in the way */
  1687.     int destroy_list_index = -1;
  1688.     int i;
  1689. #define DESTROY_CMS(cms)    xv_destroy_status(cms, DESTROY_CLEANUP)
  1690.     /*
  1691.      * Need DESTROY_CMS() to immediately clear out the CMS.
  1692.      * xv_destroy_status() was found by poking around in
  1693.      * the XView source code.  Before doing that, I tried each of:
  1694.      * xv_destroy(), xv_destroy_safe(), xv_destroy_check(), and
  1695.      * xv_destroy_immediate().  None of these did what I wanted (they
  1696.      * didn't release the CMS immediately, and subsequent creates of CMS's
  1697.      * reflected the fact that the previous ones hadn't been released).
  1698.      */
  1699. #define DESTROY_LIST_ADD(cms)    destroy_list[++destroy_list_index] = cms
  1700. #define DESTROY_LIST_DESTROY()    for (i = 0; i <= destroy_list_index; i++) \
  1701.                     DESTROY_CMS(destroy_list[i]);
  1702.     int tries;
  1703.     int skip;
  1704.     int first_index = 0;
  1705.     int cms_size;
  1706.     boolean found;
  1707.     boolean ok;
  1708.  
  1709.     for (tries = 0; tries < MAX_TRIES; tries++) {
  1710.     cms = (Cms) xv_create(XV_NULL, CMS,
  1711.         CMS_TYPE,        XV_DYNAMIC_CMS,
  1712.         CMS_SIZE,        num_colors,
  1713.         NULL);
  1714.  
  1715.     cms_index_table = (unsigned long *) xv_get(cms, CMS_INDEX_TABLE);
  1716.     cms_size = xv_get(cms, CMS_SIZE);
  1717.  
  1718.     /*
  1719.      * The code below finds the first color in the
  1720.      * table that is a multiple of num_colors.
  1721.      * Can't assume that all the real pixel values for the
  1722.      * colors acquired above are sequential and contiguous.
  1723.      * But I am assuming that the first color found that is a
  1724.      * multiple of num_colors is a reasonable starting place
  1725.      * to look.  The requirement that all the colors be sequential
  1726.      * and contiguous will be checked later in this routine.
  1727.      */
  1728.     found = FALSE;
  1729.     for (skip = 0; skip < cms_size; skip++) {
  1730.         if ((cms_index_table[skip] % num_colors) == 0) {
  1731.         found = TRUE;
  1732.         break;
  1733.         }
  1734.     }
  1735.     if (! found) {
  1736.         DESTROY_LIST_ADD(cms);
  1737.         continue;
  1738.     }
  1739.  
  1740.     dummy_cms = NULL;
  1741.     if (skip != 0) {
  1742.         /*
  1743.          * Allocate a cms with just those colorcells that need
  1744.          * to be skipped.  This will get them out of way so that
  1745.          * we can get the colorcells we need.  This dummy cms
  1746.          * will be destroyed later.
  1747.          */
  1748.         DESTROY_CMS(cms);
  1749.         dummy_cms = xv_create(XV_NULL, CMS,
  1750.                 CMS_TYPE,    XV_DYNAMIC_CMS,
  1751.                 CMS_SIZE,    skip,
  1752.                 NULL);
  1753.         DESTROY_LIST_ADD(dummy_cms);
  1754.         continue;        /* try again */
  1755.     }
  1756.  
  1757.     /*
  1758.      * Verify that all the real pixel values are contiguous.
  1759.      *
  1760.      * (The obvious way would be to subtract the first and last
  1761.      * pixel values and see if their difference is correct, but
  1762.      * this assumes that the intervening pixel values are OK.
  1763.      * I decided not to trust this assumption--best
  1764.      * to be certain by checking every pixel value.)
  1765.      */
  1766.     ok = TRUE;
  1767.     for (i = 0; i < num_colors - 1; i++) {
  1768.         if (cms_index_table[first_index + i] + 1 !=
  1769.         cms_index_table[first_index + i + 1]) {
  1770.  
  1771.         ok = FALSE;
  1772.         break;
  1773.         }
  1774.     }
  1775.     if (ok) {
  1776.         DESTROY_LIST_DESTROY();
  1777.         return(cms);        /* SUCCESS */
  1778.     }
  1779.     else {
  1780.         /*
  1781.          * Need to acquire some of the color cells and hold on to
  1782.          * them, so that they don't get in our way the next time
  1783.          * around the loop.
  1784.          */
  1785.         found = FALSE;
  1786.         for (skip = 1; skip < cms_size; skip++) {
  1787.         if ((cms_index_table[skip] % num_colors) == 0) {
  1788.             found = TRUE;
  1789.             break;
  1790.         }
  1791.         }
  1792.         if (found) {
  1793.         DESTROY_CMS(cms);
  1794.         dummy_cms = (Cms) xv_create(XV_NULL, CMS,
  1795.                 CMS_TYPE,        XV_DYNAMIC_CMS,
  1796.                 CMS_SIZE,        skip,
  1797.                 NULL);
  1798.  
  1799.         DESTROY_LIST_ADD(dummy_cms);
  1800.         }
  1801.         else {
  1802.         /* hold on to it til we succeed or fail, so that the
  1803.          * colorcells on this cms don't get in our way
  1804.          */
  1805.         DESTROY_LIST_ADD(cms);
  1806.         }
  1807.     }
  1808.     }
  1809.     DESTROY_LIST_DESTROY();
  1810.     return(NULL);            /* FAILURE */
  1811. }
  1812.